package mathematics;

import java.io.IOException;

import org.apache.commons.math.MathException;

import uci.rt.ccr1c.engine.matrix.Mat;

public class Solver
{
	
	private IFunction funz;
	static final double GAP = 1e3;
	private int step=0;
	private int maxStep=10;
	
	public Solver(IFunction funz ){
		this.funz=funz;
	}
	
	public double[] getMinimum(double[]startingPoint, double radius) throws MathException, IOException{
		double[][][] points = getGridPoint(startingPoint,radius);		
		//print(points);
		step++;
		double[] interactionResult = getInteractionResult(points, radius);
		double[] nextInteractionResult = null;
		if(step<maxStep){
			double[] newPoints= new double[]{interactionResult[0],interactionResult[1]};
			nextInteractionResult=getMinimum(newPoints,radius/4);
		}
		return nextInteractionResult;
	}
	

	private double[] getInteractionResult(double[][][] points, double radius) throws MathException, IOException
	{

		double[][] zVal = new double[(int) GAP+1][(int) GAP+1];
		double[] interactionResult = new double[3];
		interactionResult[0]=0;//x
		interactionResult[1]=0;//y
		interactionResult[2]=Double.MAX_VALUE;//min
		
		for(Integer xx =0; xx<=GAP;xx++){
			double[][] rowX = points[xx];
			for(Integer yy =0 ; yy<=GAP ; yy++){		
				double val = funz.getValue(rowX[yy]);
				zVal[xx][yy]=val;
				if(val<interactionResult[2]){
					interactionResult[2]=val;
					interactionResult[0]=rowX[yy][0];
					interactionResult[1]=rowX[yy][1];
				}
			}
		}
		//print(zVal);
		Mat z = new Mat(zVal);
		z.writeAsCsvFile("c:/R/cva/FunctionNLM"+step+".csv", ",");
		
		System.out.println("Step: "+step+"[" + interactionResult[0] +"," + interactionResult[1] +"] min: " + interactionResult[2] );
		return interactionResult;
	}

	private void print(double[][] zVal)
	{
		for(int x =0 ;x<zVal.length;x++){
			double[] rowX = zVal[x];
			StringBuffer row= new StringBuffer();
			for (int y =0;y<rowX.length;y++){
				row.append(rowX[y]+"\t");
			}
			System.out.println(row.toString());
		}
		
	}

	private void print(double[][][] points)
	{
		for(int x =0 ;x<points.length;x++){
			double[][] rowX = points[x];
			StringBuffer row= new StringBuffer();
			for (int y =0;y<rowX.length;y++){
				row.append("["+rowX[y][0]+","+rowX[y][1]+"]\t");
			}
			System.out.println(row.toString());
		}
		
	}

	private double[][][] getGridPoint(double[] startingPoint,double radius)
	{
		double[][][] res = new double[(int) GAP+1][(int) GAP+1][2];
		double x=startingPoint[0];
		double y=startingPoint[1];
		double startX =  x-radius;
		double startY = y-radius;
		double step=2*radius/GAP;
		for(Integer xx =0; xx<=GAP;xx++){
			for(Integer yy =0 ; yy<=GAP ; yy++){
				res[xx][yy][0]=startX+xx.doubleValue()*step;
				res[xx][yy][1]=startY+yy.doubleValue()*step;
			}
		}
		
		return res;
	}
}
